import request from "@/utils/request";
import { reactive, computed, toRefs } from "vue";
import { useDictStoreHook } from "@/store/modules/dictionary";

interface Pageable {
  pageNum: number;
  pageSize: number;
  total: number;
}
interface StateProps {
  tableData: any[];
  pageable: Pageable;
  searchParam: {
    [key: string]: any;
  };
  totalParam: {
    [key: string]: any;
  };
  ids?: any[];
  selections?: any[];
  loading?: boolean;
  icon?: {
    [key: string]: any;
  };
  deleteLoading?: boolean;
}

/**
 * @description table 页面操作方法封装
 * @param {Function} api 获取表格数据 api 方法 (必传)
 * @param {Object} initParam 获取数据初始化参数 (非必传，默认为{})
 * @param {Object} searchParamData 表格搜索初始化参数 (非必传，默认为{})
 * @param {Boolean} isPageable 是否有分页 (非必传，默认为true)
 * @param {Function} dataCallBack 对后台返回的数据进行处理的方法 (非必传)
 * */
export const useTable = (
  api = "",
  initParam: object = {},
  searchParamDataInit: object = {},
  isPageable = true,
  dataCallBack?: (data: any) => any,
  requestError?: (error: any) => void,
  deleteParam = { api: "", data: {} },
  pageSize1 = 10
) => {
  const state = reactive<StateProps>({
    // 表格数据
    tableData: [],
    // 分页数据
    pageable: {
      // 当前页数
      pageNum: 1,
      // 每页显示条数
      pageSize: pageSize1 ? pageSize1 : 10,
      // 总条数
      total: 0,
    },
    // 查询参数(只包括查询)
    searchParam: JSON.parse(JSON.stringify(searchParamDataInit)),
    // 初始化默认的查询参数
    // searchInitParam: searchParamDataInit,
    // 总参数(包含分页和查询参数)
    totalParam: {},
    //被选中的行
    ids: [],
    //被选中的行对象
    selections: [],
    //正在加载中
    loading: false,
    // 正在删除中
    deleteLoading: false,
  });

  /**
   * @description 分页查询参数(只包括分页和表格字段排序,其他排序方式可自行配置)
   * */
  const pageParam = computed({
    get: () => {
      return {
        pageNum: state.pageable.pageNum,
        pageSize: state.pageable.pageSize,
      };
    },
    set: (newVal: any) => {
      console.log("我是分页更新之后的值", newVal);
    },
  });

  /**
   * @description 获取表格数据
   * @return void
   * */
  const getTableList = async () => {
    if (!api) return;
    try {
      // 先把初始化参数和分页参数放到总参数里面
      Object.assign(
        state.totalParam,
        initParam,
        isPageable ? pageParam.value : {}
      );
      const params = isPageable
        ? {
            size: state.totalParam.pageSize,
            current: state.totalParam.pageNum,
            data: {
              ...state.searchParam,
            },
            ...initParam,
          }
        : {
            ...state.searchParam,
            ...initParam,
          };

      state.loading = true;
      const res: any = await request({
        url: api,
        method: "post",
        data: params,
      }).finally(() => {
        state.loading = false;
      });

      // 有处理函数，则进行返回值数据处理
      let { data } = res;
      dataCallBack && (data = dataCallBack(data));

      state.tableData = isPageable ? data : data;

      // 解构后台返回的分页数据 (如果有分页更新分页信息)
      if (isPageable) {
        const { size, current, total } = res;
        updatePageable({ pageNum: current, pageSize: size, total });
      }
    } catch (error) {
      requestError && requestError(error);
    }
  };

  /**
   * @description 更新查询参数
   * @return void
   * */
  const updatedTotalParam = () => {
    state.totalParam = {};
    // 处理查询参数，可以给查询参数加自定义前缀操作
    const nowSearchParam: StateProps["searchParam"] = {};
    // 防止手动清空输入框携带参数（这里可以自定义查询参数前缀）
    for (const key in state.searchParam) {
      // 某些情况下参数为 false/0 也应该携带参数
      if (
        state.searchParam[key] ||
        state.searchParam[key] === false ||
        state.searchParam[key] === 0
      ) {
        nowSearchParam[key] = state.searchParam[key];
      }
    }
    Object.assign(
      state.totalParam,
      nowSearchParam,
      isPageable ? pageParam.value : {}
    );
    // console.log("state.totalParam,", state.totalParam);
  };

  /**
   * @description 更新分页信息
   * @param {Object} pageable 后台返回的分页数据
   * @return void
   * */
  const updatePageable = (pageable: Pageable) => {
    Object.assign(state.pageable, pageable);
  };

  /**
   * @description 表格数据查询
   * @return void
   * */
  const search = () => {
    state.pageable.pageNum = 1;
    updatedTotalParam();
    getTableList();
  };

  /**
   * @description 表格数据重置
   * @return void
   * */
  const reset = () => {
    state.pageable.pageNum = 1;
    // 重置搜索表单的时，如果有默认搜索参数，则重置默认的搜索参数
    state.searchParam = { ...searchParamDataInit };
    updatedTotalParam();
    getTableList();
  };

  /**
   * @description 每页条数改变
   * @param {Number} val 当前条数
   * @return void
   * */
  const handleSizeChange = (val: number) => {
    state.pageable.pageNum = 1;
    state.pageable.pageSize = val;
    getTableList();
  };

  /**
   * @description 当前页改变
   * @param {Number} val 当前页
   * @return void
   * */
  const handleCurrentChange = (val: number) => {
    state.pageable.pageNum = val;
    getTableList();
  };

  /**
   * 行checkbox change事件
   *
   * @param selection
   */
  const handleSelectionChange = (selection: any) => {
    state.selections = selection;
    state.ids = selection.map((item: any) => item.id);
  };
  /**
   * 删除字典
   */
  const handleTableDelete = (dictId?: number, title?: string) => {
    if (deleteParam?.api) {
      const dictIds = [dictId || state.ids].join(",");
      if (!dictIds) {
        ElMessage.warning("请勾选删除项");
        return;
      }

      ElMessageBox.confirm(title ? title : "确认删除已选中的数据项?", "警告", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      }).then(async () => {
        const dictIdsArr = dictIds.split(",");
        const data = {
          ...deleteParam?.data,
          ids: dictIdsArr,
        };
        state.deleteLoading = true;
        await request({
          url: deleteParam.api,
          method: "post",
          data: data,
        })
          .then(() => {
            ElMessage.success("删除成功");
            // reset();
            getTableList();
          })
          .finally(() => {
            state.deleteLoading = false;
          });
      });
    } else {
      return;
    }
  };

  return {
    ...toRefs(state),
    getTableList,
    search,
    reset,
    handleSizeChange,
    handleCurrentChange,
    updatedTotalParam,
    handleSelectionChange,
    handleTableDelete,
  };
};

/**
 * @description 接收数据流生成 blob，创建链接，下载文件
 * @param {Function} api 导出表格的api方法 (必传)
 * @param {String} tempName 导出的文件名 (必传)
 * @param {Object} params 导出的参数 (默认{})
 * @param {Boolean} isNotify 是否有导出消息提示 (默认为 true)
 * @param {String} fileType 导出的文件格式 (默认为.xlsx)
 * import { useDownload } from "@/utils/commonHooks";
 * 使用 useDownload(parameter.value.tempApi, `${parameter.value.title}模板`);
 * */

export const useDownload = async (
  api: string,
  tempName: string,
  params: any = {},
  isNotify = true,
  fileType = ".xlsx"
) => {
  if (isNotify) {
    ElNotification({
      title: "温馨提示",
      message: "如果数据庞大会导致下载缓慢，请您耐心等待！",
      type: "warning",
      duration: 2000,
    });
  }
  try {
    const res: any = await request({
      url: api,
      method: "post",
      data: params,
      responseType: "arraybuffer",
    });
    const blob = new Blob([res.data]);
    // 兼容 edge 不支持 createObjectURL 方法
    if ("msSaveOrOpenBlob" in navigator)
      return window.navigator.msSaveOrOpenBlob(blob, tempName + fileType);
    const blobUrl = window.URL.createObjectURL(blob);
    const exportFile = document.createElement("a");
    exportFile.style.display = "none";
    exportFile.download = `${tempName}${fileType}`;
    exportFile.href = blobUrl;
    document.body.appendChild(exportFile);
    exportFile.click();
    // 去除下载对 url 的影响
    document.body.removeChild(exportFile);
    window.URL.revokeObjectURL(blobUrl);
  } catch (error) {
    console.log(error);
  }
};

/**
 * @description 使用数据字典表值
 * @param {String} code 字典表code
 * @param {String | Number} value 字典表回显值，不传则默认获取字典list
 * import { useDictionary } from "@/utils/commonHooks";
 * 使用 useDictionary('SexType', 1);
 * */
const dictionaryStore = useDictStoreHook();
export const useDictionary = (code: string, value?: any) => {
  if (value === undefined) {
    return dictionaryStore.filterDictList(code);
  } else {
    return dictionaryStore.filterDictName(code, value);
  }
};

/**
 * @description 获取列表规定的最高table高度（适用于常规列表页）
 * import { useComputeTableHeight } from "@/utils/useTable";
 * 使用 useComputeTableHeight();
 * */
export const useComputeTableHeight = () => {
  // 获取网页可视窗口高度
  const vhFull =
    window?.innerHeight ||
    document.documentElement.clientHeight ||
    document.body.clientHeight;
  // 搜索框高度
  const searchHeight =
    document.getElementsByClassName("search-container")[0]?.offsetHeight || 0;
  // 表格头部操作栏高度
  const tableHeaderHeight =
    document.getElementsByClassName("el-card__header")[0]?.offsetHeight || 0;
  // 表格分页
  let paginationHieght = 0;
  if (document.getElementsByClassName("el-pagination")[0]) {
    paginationHieght =
      document.getElementsByClassName("el-pagination")[0]?.offsetHeight + 20 ||
      0;
  } else {
    paginationHieght =
      document.getElementsByClassName("pagination")[0]?.offsetHeight || 0;
  }

  const result =
    vhFull -
    100 -
    10 -
    searchHeight -
    10 -
    tableHeaderHeight -
    40 -
    paginationHieght -
    10;

  return result;
};
export const useDownloadUrl = async (
  url: string,
  tempName: string,
  isNotify = false
) => {
  if (isNotify) {
    ElNotification({
      title: "温馨提示",
      message: "如果数据庞大会导致下载缓慢，请您耐心等待！",
      type: "warning",
      duration: 2000,
    });
  }
  try {
    const downloadUrl = `${uploadApi}/system/fileCenter/download/${url}`;
    const downloadElement = document.createElement("a");
    // 创建下载的链接
    downloadElement.href = `${downloadUrl}?originalFilename=${tempName}`;
    console.log(downloadElement.href);

    // 下载后文件名
    downloadElement.download = tempName;
    document.body.appendChild(downloadElement);
    // 点击下载
    downloadElement.click();
    // 下载完成移除元素
    document.body.removeChild(downloadElement);
  } catch (error) {
    console.log(error);
  }
};
